package com.tbit.uqbike.client.controller;

import cn.hutool.core.date.DateUtil;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.MachineOpLog;
import com.tbit.uqbike.center.pojo.MachineStatus;
import com.tbit.uqbike.client.business.machine_op_log.service.MachineOpLogService;
import com.tbit.uqbike.client.business.temp_power.service.TempPowerService;
import com.tbit.uqbike.client.constant.*;
import com.tbit.uqbike.client.dao.core.AppointMentDao;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.util.Assert;
import com.tbit.uqbike.client.util.GeoUtil;
import com.tbit.uqbike.client.util.ObjectUtil;
import com.tbit.uqbike.client.util.OutputUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * 终端远程控制
 *
 * @author Leon
 * 2017年2月24日 下午5:51:05
 */
@Controller
@RequestMapping("/terControl")
@Slf4j
public class TerControlController {
    @Autowired
    private TerControlService terControlService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private UserService userService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private AppointMentDao appointMentDao;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private GeoService geoService;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private ParkService parkService;
    @Autowired
    private MachineOpLogService machineOpLogService;
    @Autowired
    private TempPowerService tempPowerService;

    /**
     * 临时通电
     *
     * @param token
     */
    @PutMapping("/tempPower")
    @ResponseBody
    public Result<Integer> tempPower(String token, @RequestParam(defaultValue = "0") Integer ble, HttpServletRequest request) {
        User user = tokenService.getUser(token);
        String orderSourceHeader = request.getHeader("orderSource");
        int orderSource = 3; // 默认来源微信小程序
        try {
            orderSource = Integer.parseInt(orderSourceHeader);
        } catch (Exception ignored) {}
        tempPowerService.tempPower(user.getUserId(), user.getUserId(), ble == 1, orderSource, false);
        return Result.success();
    }

    /**
     * 临时通电（提供给其他端使用，不鉴权）
     */
    @PutMapping("/rpc/tempPower")
    @ResponseBody
    public Result<Integer> tempPower(Integer userId, Integer opId, @RequestParam(defaultValue = "0") Integer ble, HttpServletRequest request) {
        String orderSourceHeader = request.getHeader("orderSource");
        int orderSource = 3; // 默认来源微信小程序
        try {
            orderSource = Integer.parseInt(orderSourceHeader);
        } catch (Exception ignored) {}
        tempPowerService.tempPower(userId, opId, ble == 1, orderSource, true);
        return Result.success();
    }


    /**
     * 临时停车指令
     *
     * @param token
     * @param type    控制类型 0关锁 1开锁
     * @param request
     * @return
     */
    @RequestMapping("/park")
    @ResponseBody
    public Result park(String token, @RequestParam(defaultValue = "0") Integer type, HttpServletRequest request) {
        User user = tokenService.getUser(token);
        MachineBorrow machineBorrow = machineBorrowService.getByUserId(user.getUserId());
        if (machineBorrow == null) {
            throw new BaseException("骑行记录不存在");
        }
        Machine machine = machineService.getByMachineId(machineBorrow.getMachineId());
        if (machine == null) {
            throw new BaseException("设备不存在");
        }
        String serNO = UUID.randomUUID().toString();
        String header = request.getHeader("orderSource");
        Integer orderSource;
        //默认来源微信小程序
        if (header == null) {
            orderSource = 3;
        } else {
            orderSource = (Integer.valueOf(header));
        }
        if (type == 0) {
            terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_CONTROL,
                    ControlTypeConstant.CONTROL_CLOSE_HUB, "", machine, false, orderSource, user.getUserId(),
                    "用户关锁");
        } else {
            terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_CONTROL,
                    ControlTypeConstant.CONTROL_TYPE_CONTINUERIDE, "", machine, false, orderSource, user.getUserId(),
                    "用户开锁");
            parkService.delByMachineId(machine.getMachineId());
        }
        return Result.success();
    }

    /**
     * 远程控制
     *
     * @param machineNO   设备编号
     * @param controlType 控制类型
     * @param paramName   参数名称
     * @param paramValue  参数值
     * @param orderSource 订单来源
     * @param token       令牌
     * @param session     会话
     * @param response    响应
     * @ignoreParams request
     */
    @RequestMapping("/sendControl")
    public void sendControl(String machineNO, String userCode, String controlType, String paramName, String paramValue, Integer orderSource, String token, Double lon, Double lat, Integer mapType,
                            HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {

            Assert.hasLength(controlType, "-50001", "controlType不能为空");
            Assert.hasLength(paramName, "-50002", "paramName不能为空");

            User user = tokenService.getUser(token);

            /**生成流水号*/
            String serNO = UUID.randomUUID().toString();
            Machine machine;
            if (StringUtils.isNotEmpty(userCode)) {
                userCode = userCode.trim();
                machine = machineService.getByUserCode(userCode);
            } else {
                Assert.hasLength(machineNO, "-30001", "machineNO不能为空");
                machineNO = machineNO.trim();
                machine = machineService.getByMachineNO(machineNO);
            }
            if (machine == null) {
                throw new BaseException("-30005", "设备不存在");
            }
            machineNO = machine.getMachineNO();
            /***/
            if (SystemData.controlMap.containsKey(controlType + "." + paramName) || "voice".equals(controlType)) {
                if (paramName.equals(ControlTypeConstant.CONTROL_TYPE_OPEN_HELMET)) {
                    //添加未借车不能开启头盔锁功能
                    MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
                    if (machineBorrow == null) {
                        throw new BaseException("-3006", "用户未借车，无法开启头盔锁");
                    }
                    //5.0.0 增加还车 10 秒内 限制头盔锁解锁
                    String limit = redisService.get(String.format(RedisConstant.RETURN_LIMIT_HELMET, machineBorrow.getOrderNO()));
                    if (Objects.nonNull(limit)){
                        throw new BaseException("订单触发还车后限制开头盔锁10S，请稍后重试");
                    }

                    redisService.add(RedisConstant.USER_OPEN_HELMET + machine.getMachineId(), DateUtil.now(), 24 * 3600);
                    redisService.del(FunctionConstant.CARSTATUSEX + machine.getMachineNO());
                    redisService.del(FunctionConstant.CARSTATUS + machine.getMachineNO());
                }
                if (ControlTypeConstant.CONTROL_TYPE_FIND.equals(paramName)) {
                    AppointMent appointMent = appointMentDao.getByMachineId(machine.getMachineId());
                    if (appointMent != null && !appointMent.getUserId().equals(user.getUserId())) {
                        throw new BaseException("-160004", "该车辆已被预约，请换一台车");
                    }
                    if (mapType == null) {
                        mapType = MapConstant.MAP_GOOGLE;
                    }
                    if (lon == null || lat == null) {
                        throw new BaseException("-2001", "获取位置信息失败，请打开定位后重试");
                    }
                    /**寻车距离限制*/
                    MachineStatus machineStatus = machineStatusService.getByMachineNO(machine.getMachineNO(), MapConstant.MAP_BAIDU);
                    if (machineStatus == null || machineStatus.getLon() == null || machineStatus.getLat() == null) {
                        throw new BaseException("-3029", "故障车辆，车辆还没有上线");
                    }
                    Point point = new Point(machineStatus.getLon(), machineStatus.getLat());
                    Boolean isInArea = geoService.checkInGeo(machine.getAccountId(), point);
                    if (!isInArea) {
                        throw new BaseException("-3047", "运营区域外禁止借车");
                    }
                    Point pointDB = new Point(lon, lat);
                    pointDB = calibrateService.calibrate(pointDB, mapType, SysConstant.ORIGINAL);
                    Double distance = GeoUtil.getPointDistance(point, pointDB);
                    log.info("设备位置" + point + "手机位置" + pointDB + "距离" + distance);
                    if (distance >= 500) {
                        throw new BaseException("-160010", "当前位置距离车辆较远，请在车辆附近操作");
                    }
                }
                if (ControlTypeConstant.CONTROL_TYPE_CLOSE_HELMET.equals(paramName)) {
                    //兼容已上锁状态的头盔不重复发上锁指令
                    String carStatus = redisService.get(FunctionConstant.CARSTATUSEX + machine.getMachineNO());
                    if (StringUtils.isNotEmpty(carStatus)) {
                        Integer terStatus = Integer.valueOf(carStatus);
                        log.info("machineNO={},terStatus={}", machineNO, terStatus);
                        if (ObjectUtil.statusParse(3, terStatus) && ObjectUtil.statusParse(11, terStatus)) {
                            log.info(machineNO + "下发关闭头盔指令");
                            terControlService.sendControl(serNO, machineNO, controlType, paramName, paramValue, machine, false, orderSource, user.getUserId(), "临停下发关闭头盔锁");
                        } else {
                            log.info(machineNO + "头盔已上锁,不发送关闭头盔锁指令");
                        }
                    } else {
                        //5.1.0版本新增功能，骑行中新增下发关头盔锁指令
                        log.info(machineNO + "获取不到车辆状态,下发关闭头盔指令");
                        terControlService.sendControl(serNO, machineNO, controlType, paramName, paramValue, machine, false, orderSource, user.getUserId(), "骑行中下发关闭头盔锁");
                    }
                } else {
                    /**头盔锁指令下发记录*/
                    terControlService.sendControl(serNO, machineNO, controlType, paramName, paramValue, machine, false, orderSource, user.getUserId(), "用户主动指令操作");
                }
                /**记录日志信息*/
				/*OrderLog orderLog = new OrderLog();
				orderLog.setOrderSerNo(serNO);
				orderLog.setMachineId(machine.getMachineId());
				orderLog.setMachineNo(machine.getMachineNO());
				orderLog.setUserCode(machine.getUserCode());
				orderLog.setChannelType(Integer.valueOf(ControlWay.CLIENT_GPRS.getCode()));
				orderLog.setBusinessType(Integer.valueOf(paramName));
				orderLog.setOpTime(DateTimeUtil.getNowTime());
				orderLog.setOpType(OrderLogTypeConstant.OPTYPE_USER);
				orderLog.setOrderContent(Integer.valueOf(paramName));
				orderLog.setOrderSource(orderSource);
				orderLog.setOrderType(1);
				orderLog.setOpId(user.getUserId());
				orderLog.setRemark("用户主动指令操作");
				orderLog.setAccountUserId(machine.getAccountId());
				orderLogService.insert(orderLog);*/

                // 插入车辆操作日志
                MachineOpLog.MachineOpLogBuilder logBuilder = getByControlType(paramName);
                if (logBuilder != null) {
                    String detail = "指令流水号: " + serNO;
                    machineOpLogService.insertSingle(logBuilder
                            .accountId(machine.getAccountId())
                            .machineId(machine.getMachineId())
                            .machineNO(machine.getMachineNO())
                            .userCode(machine.getUserCode())
                            .opUser(user.getName())
                            .opUserPhone(user.getPhone())
                            .detail(detail)
                            .build());
                }
            } else {
                throw new BaseException("-1003", "无权操作");
            }

            map.put(ResponseCode.RET, ResponseCode.SUCC);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }

    private MachineOpLog.MachineOpLogBuilder getByControlType(String controlType) {
        String op = null;
        String opType = null;
        switch (controlType) {
            case ControlTypeConstant.CONTROL_TYPE_OPEN_HELMET:
                op = "头盔锁";
                opType = "开启";
                break;
            case ControlTypeConstant.CONTROL_TYPE_CLOSE_HELMET:
                op = "头盔锁";
                opType = "关闭";
                break;
            case ControlTypeConstant.CONTROL_TYPE_LOCATION:
                op = "定位";
                break;
            case ControlTypeConstant.CONTROL_TYPE_FIND:
                op = "寻车";
                break;
        }
        if (op == null) {
            return null;
        }
        return MachineOpLog.builder()
                .operation(op)
                .opType(opType)
                .opPlatform(OperationPlatform.CLIENT.code)
                .result(true)
                .opTime(LocalDateTime.now());
    }

    /**
     * 打开关闭电池锁
     *
     * @param userCode    车辆编号
     * @param controlType 控制类型
     * @param paramName   值
     * @param paramValue  value
     * @param orderSource 来源
     * @param token       令牌
     * @param session     会话
     * @param response    响应
     * @ignoreParams request
     */
    @RequestMapping("/control")
    public void control(String userCode, String controlType, String paramName, String paramValue, Integer orderSource, String token,
                        HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.hasLength(userCode, "-30001", "machineNO不能为空");
            Assert.hasLength(controlType, "-50001", "controlType不能为空");
            Assert.hasLength(paramName, "-50002", "paramName不能为空");

            User user = tokenService.getUser(token);
            /**生成流水号*/
            String serNO = UUID.randomUUID().toString();
            Machine machine = machineService.getByUserCode(userCode);
            if (machine == null) {
                throw new BaseException("-30005", "设备不存在");
            }
            User userDB = userService.getByUserId(user.getUserId());
            /**只有学生认证的用户才有权操作*/
            if (!userDB.getStudentAuth()) {
                throw new BaseException("-3040", "请先学生认证");
            }
            /**只开发打开电池锁，关闭电池锁*/
            if ((controlType.equals("control") && paramName.equals(ControlTypeConstant.CONTROL_TYPE_BATTERYDE) ||
                    (controlType.equals("control") && paramName.equals(ControlTypeConstant.CONTROL_TYPE_BATTERYRIDE)))) {
                terControlService.sendControl(serNO, machine.getMachineNO(), controlType, paramName, paramValue, machine, false, orderSource, user.getUserId(), "用户操作电池锁");
                /**记录日志信息*/
				/*OrderLog orderLog = new OrderLog();
				orderLog.setOrderSerNo(serNO);
				orderLog.setMachineId(machine.getMachineId());
				orderLog.setMachineNo(machine.getMachineNO());
				orderLog.setUserCode(machine.getUserCode());
				orderLog.setChannelType(Integer.valueOf(ControlWay.CLIENT_GPRS.getCode()));
				orderLog.setBusinessType(Integer.valueOf(paramName));
				orderLog.setOpTime(DateTimeUtil.getNowTime());
				orderLog.setOpType(OrderLogTypeConstant.OPTYPE_USER);
				orderLog.setOrderContent(Integer.valueOf(paramName));
				orderLog.setOrderSource(orderSource);
				orderLog.setOrderType(1);
				orderLog.setOpId(user.getUserId());
				orderLog.setRemark("用户操作电池锁");
				orderLog.setAccountUserId(machine.getAccountId());
				orderLogService.insert(orderLog);*/
            } else {
                throw new BaseException("-1003", "无权操作");
            }

            map.put(ResponseCode.RET, ResponseCode.SUCC);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }

}